package com.wushijia.java8.concurrent;

import static java.util.concurrent.Executors.newFixedThreadPool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;

/**
 * @author Benjamin Winterberg
 */
public class Atomic1 {

  private static final int NUM_INCREMENTS = 1000;

  private static AtomicInteger atomicInt = new AtomicInteger(0);

  public static void main(String[] args) {
    testIncrement();
    testAccumulate();
    testUpdate();
  }

  private static void testUpdate() {
    atomicInt.set(0);

    ExecutorService executor = newFixedThreadPool(2);

    IntStream.range(0, NUM_INCREMENTS)
        .forEach(i -> {
          Runnable task = () ->
              atomicInt.updateAndGet(n -> n + 2);
          executor.submit(task);
        });

    ConcurrentUtils.stop(executor);

    System.out.format("Update: %d\n", atomicInt.get());
  }

  private static void testAccumulate() {
    atomicInt.set(0);

    ExecutorService executor = newFixedThreadPool(2);

    IntStream.range(0, NUM_INCREMENTS)
        .forEach(i -> {
          Runnable task = () ->
              atomicInt.accumulateAndGet(i, (n, m) -> n + m);
          executor.submit(task);
        });

    ConcurrentUtils.stop(executor);

    System.out.format("Accumulate: %d\n", atomicInt.get());
  }

  private static void testIncrement() {
    atomicInt.set(0);

    ExecutorService executor = newFixedThreadPool(2);

    IntStream.range(0, NUM_INCREMENTS)
        .forEach(i -> executor.submit(atomicInt::incrementAndGet));

    ConcurrentUtils.stop(executor);

    System.out.format("Increment: Expected=%d; Is=%d\n", NUM_INCREMENTS, atomicInt.get());
  }

}
